/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */



/**
 *
 * @author andres
 */
package proycomplejidadopt;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import lpsolve.*;


public class Solucionador {
    
    private int [][] costosPSBod; //Costo de envio por unidad del PS i a la bodega j.
    private int [][] costosBodPD; //Costo de envio por unidad de la bodega i al PD j.
    private int [][] costosPSPD;  //Costo de envio por unidad del PD i al PS j.
    private int [] costoBodegas;
    private int [] capacidadBodegas; 
    private int [] unidadesProdPS; //Cantidad de unidades que producen los PS
    private int [] unidadesReqPD; //Cantidad de unidades requeridas por los PD
    
    private int [][] colModeloPSBod; //Cantidad unidades enviadas del PS i a la bodega j.
    private int [][] colModeloBodPD; //Cantidad unidades enviadas de la bodega i al PD j.
    private int [][] colModeloPSPD;  //Cantidad unidades enviadas del PS i al PD j.
    private int [] varsBinarias; //variables 1/0 que define si se usa o no la bodega i.
    private double variablesSolucion[];
    private double valorFuncObjetivo;
    private final int M=100000000;
    
    private int numBodegas,numPtsSum, numPtsDem;
    private int numVarsModelo,numVarsUnidPSBod,numVarsUnidBodPD,numVarsUnidPSPD;
    private LpSolve lp;
    
    Solucionador()
    {
        numBodegas=numPtsSum=numPtsDem=numVarsModelo=0;
        numVarsModelo=numVarsUnidPSBod=numVarsUnidBodPD=numVarsUnidPSPD=0;       
    }

    public void inicializar()
    {
        colModeloPSBod=new int[numPtsSum][numBodegas];
        colModeloBodPD=new int[numBodegas][numPtsDem];
        colModeloPSPD=new int[numPtsSum][numPtsDem];
        
        capacidadBodegas=new int[numBodegas];
        costoBodegas=new int[numBodegas];
        
        costosPSBod=new int[numPtsSum][numBodegas];
        costosBodPD=new int[numBodegas][numPtsDem];
        costosPSPD=new int[numPtsSum][numPtsDem];
        
        varsBinarias=new int[numBodegas];
        
        unidadesProdPS=new int[numPtsSum];
        unidadesReqPD=new int[numPtsDem];
    }
    
    //Metodo donde se agregan todas las variables del modelo, y se nombran
    public void agregarVariablesMod()
    {
        
        //se agregan las variables binarias por bodega.
        for(int i=1; i<=numBodegas ; i++)
        {
            try {
                lp.setColName(i, "b"+i);
            } catch (LpSolveException ex) {
                Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
        //se agregan las variables de la cantidad de unidades enviadas de PS->Bod.
        int cols=numBodegas+1;
   
        
        for(int i=0; i<numBodegas ; i++)
        {
            for(int j=0; j< numPtsSum; j++)
            {
                try 
                {
                    lp.setColName(cols, "x"+j+""+i);
                    colModeloPSBod[j][i]=cols;
                    cols++;
                }catch (LpSolveException ex) 
                {
                    Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
                }                
            }
        }
        
      //se agregan las variables de la cantidad de unidades enviadas de Bod->PD.

        for(int i=0; i<numBodegas; i++)
        {
            for(int j=0; j<numPtsDem; j++)
            {
                try
                {
                    lp.setColName(cols, "y"+i+""+j);
                    colModeloBodPD[i][j]=cols;
                    cols++;
                } catch (LpSolveException ex) {
                    Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        
        //se agregan las variables de la cantidad de unidades enviadas de PS->PD.

        for(int i=0; i<numPtsSum  ; i++)
        {
            for(int j=0; j<numPtsDem ; j++)
            {
                try {
                    lp.setColName(cols, "w"+i+""+j);
                    colModeloPSPD[i][j]=cols;
                    cols++;
                } catch (LpSolveException ex) {
                    Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
    
    public int resolver()
    {
        variablesSolucion=new double[numVarsModelo];
        int salida=-5;
        try {
            salida=lp.solve();
            if(salida==lp.OPTIMAL){
                valorFuncObjetivo=lp.getObjective();
                System.out.println("Objetivo= "+valorFuncObjetivo);
                lp.getVariables(variablesSolucion);
                
                for (int i = 0; i < numVarsModelo; i++) {
                    System.out.println(lp.getColName(i+1)+" "+variablesSolucion[i]);
                }
            }
            
        } catch (LpSolveException ex) {
            Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
        }  
        return salida;
        
    }
    public void agregarRestriccionesMod()
    {
        lp.setAddRowmode(true);
        int [] colNo=new int[numVarsModelo];
        double [] row=new double[numVarsModelo];
        
        //restriccion (x + w = prod. PSi). Cantidad de restric= num pts Sum.
        for(int i=0; i< numPtsSum; i++)
        {
            //recorremos por bodegas porq asi se armó el modelo.
            //Para hallar meter el respectivo Xij en la restriccion, del PSi a la bod j, en el modelo.
            for (int j = 0; j < numBodegas; j++) 
            {
                colNo[colModeloPSBod[i][j]-1]=colModeloPSBod[i][j];
                row[colModeloPSBod[i][j]-1]=1;
                try {
                    lp.setInt(colModeloPSBod[i][j], true);
                } catch (LpSolveException ex) {
                    Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            
            //Para hallar meter el respectivo Wij en la restriccion.
            for (int j = 0; j < numPtsDem; j++) 
            {
                colNo[colModeloPSPD[i][j]-1]=colModeloPSPD[i][j];
                row[colModeloPSPD[i][j]-1]=1;
                try {
                    lp.setInt(colModeloPSPD[i][j], true);
                } catch (LpSolveException ex) {
                    Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            
            try 
            {
                lp.addConstraintex(numVarsModelo, row, colNo, LpSolve.EQ, unidadesProdPS[i]);
            } catch (LpSolveException ex) 
            {
                Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            Arrays.fill(colNo, 0);
            Arrays.fill(row, 0);
        }
    
        //restriccion (y + w = req. PDi). Cantidad de restric= num pts Dem.
        for (int i = 0; i < numPtsDem; i++) 
        {
            //Para meter el respectivo Yij en la restriccion.
           for (int j = 0; j < numBodegas; j++) 
            {
                colNo[colModeloBodPD[j][i]-1]=colModeloBodPD[j][i];
                row[colModeloBodPD[j][i]-1]=1;
                try {
                    lp.setInt(colModeloBodPD[j][i], true);
                } catch (LpSolveException ex) {
                    Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            //Para hallar meter el respectivo Wij en la restriccion.
            for (int j = 0; j < numPtsSum; j++) 
            {
                colNo[colModeloPSPD[j][i]-1]=colModeloPSPD[j][i];
                row[colModeloPSPD[j][i]-1]=1;
            }
            
            try 
            {
                lp.addConstraintex(numVarsModelo, row, colNo, LpSolve.EQ, unidadesReqPD[i]);
            } catch (LpSolveException ex) 
            {
                Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            Arrays.fill(colNo, 0);
            Arrays.fill(row, 0);
        }
        ///sumatoria Xij <= capBodega
        for (int i = 0; i <numBodegas; i++) 
        {
            //Para hallar meter el respectivo Xij en la restriccion, del PSi a la bod j, en el modelo.
            for(int j=0; j< numPtsSum; j++)
            {
                colNo[colModeloPSBod[j][i]-1]=colModeloPSBod[j][i];
                row[colModeloPSBod[j][i]-1]=1;
            }
            
            try 
            {
                lp.addConstraintex(numVarsModelo, row, colNo, LpSolve.LE, capacidadBodegas[i]);
            } catch (LpSolveException ex) 
            {
                Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            
            
            Arrays.fill(colNo, 0);
            Arrays.fill(row, 0);
        }
        // sum(Xij)- sum(Yij) >= 0
        for (int i = 0; i < numBodegas;i++) {
            
            for(int j=0; j< numPtsSum; j++)
            {
                colNo[colModeloPSBod[j][i]-1]=colModeloPSBod[j][i];
                row[colModeloPSBod[j][i]-1]=1;
            }
        
            for (int j = 0; j < numPtsDem; j++) 
            {
                 colNo[colModeloBodPD[i][j]-1]=colModeloBodPD[i][j];
                 row[colModeloBodPD[i][j]-1]=-1;
            }
            
            try 
            {
                lp.addConstraintex(numVarsModelo, row, colNo, LpSolve.GE, 0);
            } catch (LpSolveException ex) 
            {
                Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
            } 
            Arrays.fill(colNo, 0);
            Arrays.fill(row, 0);
            
        }
        
        
        for (int i = 0; i < numBodegas;i++) 
        {
            //se agregan los Xij a la restriccion  M*bi - sum(Xij) >= 0
            for(int j=0; j< numPtsSum; j++)
            {
                colNo[colModeloPSBod[j][i]-1]=colModeloPSBod[j][i];
                row[colModeloPSBod[j][i]-1]=-1;
            }
            colNo[i]=i+1;
            row[i]=M;
            
            try { 
                lp.addConstraintex(numVarsModelo, row, colNo, LpSolve.GE, 0);
                lp.setInt(i+1, true);// se fija a entero cada bi de cada bodega.
                
            } catch (LpSolveException ex) {
                Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            Arrays.fill(colNo, 0);
            Arrays.fill(row, 0);
            
             //se agregan los Yij a la restriccion  M*bi - sum(Yij) >= 0
            for (int j = 0; j < numPtsDem; j++) 
            {
                 colNo[colModeloBodPD[i][j]-1]=colModeloBodPD[i][j];
                 row[colModeloBodPD[i][j]-1]=-1;
            }
            colNo[i]=i+1;
            row[i]=M;
            
            try { 
                lp.addConstraintex(numVarsModelo, row, colNo, LpSolve.GE, 0);
                
            } catch (LpSolveException ex) {
                Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
            }
            Arrays.fill(colNo, 0);
            Arrays.fill(row, 0);
        }
        
        //Se agregan las bi para la restriccion sum(bi)=1 
        for (int i = 1; i < numBodegas+1;i++) {
            colNo[i-1]=i;
            row[i-1]=1;
        }
        try { 
            lp.addConstraintex(numVarsModelo, row, colNo, LpSolve.EQ, 1);

        } catch (LpSolveException ex) {
            Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
        }
        Arrays.fill(colNo, 0);
        Arrays.fill(row, 0);
        lp.setAddRowmode(false);
        
    }
    public  void agregarFuncionObejtivo()
    {
        try {
            int [] colNo=new int[numVarsModelo];
            double [] row=new double[numVarsModelo];
            
            for (int j = 0; j < numBodegas; j++) {
                colNo[j]=j+1;
                row[j]=costoBodegas[j];

            }
            for (int i = 0; i < numBodegas;i++) {
                
                for(int j=0; j< numPtsSum; j++)
                {
                    colNo[colModeloPSBod[j][i]-1]=colModeloPSBod[j][i];
                    row[colModeloPSBod[j][i]-1]=costosPSBod[j][i];
                }
                for (int j = 0; j < numPtsDem; j++) 
                {
                     colNo[colModeloBodPD[i][j]-1]=colModeloBodPD[i][j];
                     row[colModeloBodPD[i][j]-1]=costosBodPD[i][j];
                }
            }
            for (int i = 0; i < numPtsSum; i++) {
                for (int j = 0; j < numPtsDem; j++) {
                    colNo[colModeloPSPD[i][j]-1]=colModeloPSPD[i][j];
                     row[colModeloPSPD[i][j]-1]=costosPSPD[i][j];
                }
            }
            
            lp.setObjFnex(numVarsModelo, row, colNo);
                    
            Arrays.fill(colNo, 0);
            Arrays.fill(row, 0);
            
            lp.setMinim();
            lp.writeLp("modeloGenerado.lp");// se genera un archivo q contiene el modelo.
        } catch (LpSolveException ex) {
            Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
    
    public void crearModelo()
    {
        numVarsUnidPSBod=numPtsSum*numBodegas;
        numVarsUnidBodPD=numBodegas*numPtsDem;
        numVarsUnidPSPD=numPtsSum*numPtsDem;
        numVarsModelo=numVarsUnidPSBod+numVarsUnidBodPD+numVarsUnidPSPD+numBodegas;
        
        try {
            lp=LpSolve.makeLp(0, numVarsModelo);
        } catch (LpSolveException ex) {
            Logger.getLogger(Solucionador.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        if(lp.getLp()!= 0)
        {
            agregarVariablesMod();
            agregarRestriccionesMod();
            agregarFuncionObejtivo();
        }
        else
        {
             System.out.println("No se pudo crear el modelo.");
        }
        
    }
    
    public double [] obtenerVariablesSol()
    {
	return variablesSolucion;
    }
    
    public void obtenerFuncObjetivo()
    {
        
    }
    
    
    public int[][] getCostosBodPD() {
        return costosBodPD;
    }

    public void setCostoBodPD(int i, int j, int costo)
    {
        this.costosBodPD[i][j]=costo;
    }
    
    public int[][] getCostosPSBod() {
        return costosPSBod;
    }
    
    public void setCostoPSBod(int i, int j, int costo)
    {
        this.costosPSBod[i][j]=costo;
    }

    public int[][] getCostosPSPD() {
        return costosPSPD;
    }
    
    public void setCostoPSPD(int i, int j, int costo)
    {
        this.costosPSPD[i][j]=costo;
    }

    public void setCapacidadBodegas(int pos, int capacidadBodegas) {
        this.capacidadBodegas[pos] = capacidadBodegas;
    }

    public void setCostoBodegas(int pos, int costoBodegas) {
        this.costoBodegas[pos] = costoBodegas;
    }
    
    public void setUnidadesProdPS(int pos, int produccion)
    {
        unidadesProdPS[pos]=produccion;
    }
    
    public void setUnidadesReqPD(int pos, int Urequeridas)
    {
        unidadesReqPD[pos]=Urequeridas;
    }

    public int getNumBodegas() {
        return numBodegas;
    }

    public void setNumBodegas(int numBodegas) {
        this.numBodegas = numBodegas;
    }

    public int getNumPtsDem() {
        return numPtsDem;
    }

    public void setNumPtsDem(int numPtsDem) {
        this.numPtsDem = numPtsDem;
    }

    public int getNumPtsSum() {
        return numPtsSum;
    }

    public void setNumPtsSum(int numPtsSum) {
        this.numPtsSum = numPtsSum;
    }

    public int[] getVarsBinarias() {
        return varsBinarias;
    }
    
    public int getNumVarsModelo()
    {
        return numVarsModelo;
    }

    public int[][] getColModeloBodPD() {
        return colModeloBodPD;
    }

    public void setColModeloBodPD(int[][] colModeloBodPD) {
        this.colModeloBodPD = colModeloBodPD;
    }

    public int[][] getColModeloPSBod() {
        return colModeloPSBod;
    }

    public void setColModeloPSBod(int[][] colModeloPSBod) {
        this.colModeloPSBod = colModeloPSBod;
    }

    public int[][] getColModeloPSPD() {
        return colModeloPSPD;
    }

    public void setColModeloPSPD(int[][] colModeloPSPD) {
        this.colModeloPSPD = colModeloPSPD;
    }

    public int[] getCapacidadBodegas() {
        return capacidadBodegas;
    }

    public void setCapacidadBodegas(int[] capacidadBodegas) {
        this.capacidadBodegas = capacidadBodegas;
    }

    public int[] getCostoBodegas() {
        return costoBodegas;
    }

    public void setCostoBodegas(int[] costoBodegas) {
        this.costoBodegas = costoBodegas;
    }

    public int[] getUnidadesProdPS() {
        return unidadesProdPS;
    }

    public void setUnidadesProdPS(int[] unidadesProdPS) {
        this.unidadesProdPS = unidadesProdPS;
    }

    public int[] getUnidadesReqPD() {
        return unidadesReqPD;
    }

    public void setUnidadesReqPD(int[] unidadesReqPD) {
        this.unidadesReqPD = unidadesReqPD;
    }

    public double getValorFuncObjetivo() {
        return valorFuncObjetivo;
    }
    
}
